package cn.itbox.example.application.test;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.BitSet;

/**
 * @BelongProject springboot-study
 * @BelongPackage cn.itbox.example.application.test
 * @Description TODO
 * @ClassName IPInSubnetChecker
 * @Author huyanbing
 * @Date 2024/3/11 16:40
 * @Version 1.0.0
 */
public class IPInSubnetChecker {

    public static boolean isIpInSubnet(String clientIp, String subnet) throws UnknownHostException {
        // 分离CIDR表示法中的IP地址和前缀长度
        String[] parts = subnet.split("/");
        if (parts.length != 2) {
            throw new IllegalArgumentException("Invalid CIDR format");
        }
        String baseIp = parts[0];
        int prefixLength = Integer.parseInt(parts[1]);

        // 将IP地址转换为字节数组
        InetAddress ip = InetAddress.getByName(clientIp);
        byte[] clientBytes = ip.getAddress();
        byte[] baseBytes = InetAddress.getByName(baseIp).getAddress();

        // 创建位集以处理前缀匹配
        BitSet clientBits = toBitSet(clientBytes);
        BitSet baseBits = toBitSet(baseBytes);

        // 根据前缀长度设置掩码
        for (int i = prefixLength; i < 32; i++) {
            baseBits.clear(i);
        }

        // 检查客户端IP与子网掩码按位与后是否等于子网的网络部分
        BitSet maskedClientBits = (BitSet) clientBits.clone();
        maskedClientBits.and(baseBits);
        return maskedClientBits.equals(baseBits);
    }

    private static BitSet toBitSet(byte[] bytes) {
        BitSet bits = new BitSet(32);
        for (int i = 0; i < bytes.length * 8; i++) {
            if ((bytes[i / 8] & (1 << (7 - (i % 8)))) != 0) {
                bits.set(i);
            }
        }
        return bits;
    }

    public static void main(String[] args) throws UnknownHostException {
        String clientIpAddress = "101.226.103.10";
        String subnetToCheck = "101.226.103.0/25";

        if (isIpInSubnet(clientIpAddress, subnetToCheck)) {
            System.out.println(clientIpAddress + " is in the subnet " + subnetToCheck);
        } else {
            System.out.println(clientIpAddress + " is not in the subnet " + subnetToCheck);
        }
    }
}